package com.sunrise.xdoc.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;

import org.primefaces.context.RequestContext;

import com.sunrise.xdoc.entity.AbstractIdEntity;
import com.sunrise.xdoc.event.EventData;
import com.sunrise.xdoc.event.EventManager;
import com.sunrise.xdoc.helper.DaoHelper;
import com.sunrise.xdoc.utils.SunriseClassUtils;

/**
 * The abstract class for List and Details view.
 * 
 * @param <T>
 *            entity class
 * @author PhanHongPhuc
 */
public abstract class AbstractView<T extends AbstractIdEntity> implements Serializable {
	private static final long serialVersionUID = 1402635417863338564L;

	private T[] selectedEntities;

	private T editedEntity;

	private AbstractListDataModel<T> dataModel;

	@ManagedProperty(value = "#{daoHelper}")
	private DaoHelper daoHelper;

	@SuppressWarnings("unchecked")
	@PostConstruct
	protected void init() {
		FacesContext context = FacesContext.getCurrentInstance();
		dataModel = context.getApplication().evaluateExpressionGet(context, "#{" + getDataModelBeanName() + "}",
				AbstractListDataModel.class);
	}

	protected abstract String getDataModelBeanName();

	public AbstractListDataModel<T> getDataModel() {
		return dataModel;
	}

	@SuppressWarnings("unchecked")
	protected Class<T> getEntityClass() {
		return (Class<T>) SunriseClassUtils.getArgumentClass(getClass());
	}

	public void newAction() throws InstantiationException, IllegalAccessException {
		editedEntity = getEntityClass().newInstance();
	}

	public void editAction() {
		setEditedEntity(selectedEntities[0]);
		reset();
	}

	/**
	 * Save or update editedEntity. <br/>
	 * Fire event "saveOrUpdate" + simple entityName.
	 */
	public void saveOrUpdate() {
		getDaoHelper().getDao(getEntityClass()).saveOrUpdate(editedEntity);
		EventManager.fireEvent("saveOrUpdate" + getEntityClass().getSimpleName(), new EventData(this, editedEntity));
	}

	/**
	 * Delete selected entities. <br/>
	 * Fire event "delete" + simple entityName.
	 */
	public void deleteAction() {
		getDaoHelper().getDao(getEntityClass()).deleteAll(Arrays.asList(selectedEntities));
		EventManager.fireEvent("delete" + getEntityClass().getSimpleName(), new EventData(this, selectedEntities));
	}

	public List<Long> getSelectedEntityIds() {
		List<Long> ids = new ArrayList<>(selectedEntities.length);
		for (T entity : selectedEntities) {
			ids.add(entity.getId());
		}
		return ids;
	}

	/**
	 * The function to reset the detail form when the validation fails, to avoid
	 * it keep the invalid state.
	 * 
	 * @see http://www.primefaces.org/showcase/ui/resetInput.jsf
	 */
	public void reset() {
		RequestContext.getCurrentInstance().reset(getDetailPanelViewId());
	}

	protected abstract String getDetailPanelViewId();

	public DaoHelper getDaoHelper() {
		return daoHelper;
	}

	public void setDaoHelper(DaoHelper daoHelper) {
		this.daoHelper = daoHelper;
	}

	public T[] getSelectedEntities() {
		return selectedEntities;
	}

	public void setSelectedEntities(T[] selectedEntities) {
		this.selectedEntities = selectedEntities;
	}

	public T getEditedEntity() {
		return editedEntity;
	}

	public void setEditedEntity(T editedEntity) {
		this.editedEntity = editedEntity;
	}
}
